package org.flexharmony.harmonizer.javadef;

import static org.flexharmony.harmonizer.utils.CommonMethods.*;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.flexharmony.ASClass;

/**
 * Represent a Java class definition parsed from bytecode.
 * 
 * @author Corey Baswell
 */
public class JavaClassDefinition
{
  /**
   * The type for this class.
   */
  public final JavaType type;
  
  /**
   * The {@link ASClass} annotation on this class if present or <code>null</code>.
   */
  public final ASClass asClass;

  /**
   * List of fields for this class.
   */
  public final List<JavaFieldDefinition> fields;
  
  /**
   * List of methods for this class.
   */
  public final List<JavaMethodSignature> methodSignatures;
  
  public JavaClassDefinition(JavaType type, ASClass asClass, List<JavaFieldDefinition> fields, 
      List<JavaMethodSignature> methodSignatures)
  {
    this.type = type;
    this.asClass = asClass;
    this.fields = Collections.unmodifiableList(fields);
    this.methodSignatures = Collections.unmodifiableList(methodSignatures);
  }
  
  /**
   * Check to see if public getter and setter methods exists for the given
   * field definition.
   * 
   * @param fieldDef
   * @return <code>true</code> if public getter and setter bean access methods exists
   * for the given field definition. <code>false</code> otherwise.
   */
  public boolean hasPublicBeanAccessors(JavaFieldDefinition fieldDef)
  {
    String fieldName = fieldDef.name;
    String typeName = fieldDef.type.qName.toString();
    
    String funcName = (fieldName.length() > 1) 
    ? fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, fieldName.length()) 
    : fieldName;
    
    JavaMethodSignature getter = getMethod(JavaVisibility.PUBLIC, ("get" + funcName), null, fieldDef.type);
    
    if ((getter == null) && ((typeName.equals("java.lang.Boolean") || typeName.equals("Z"))))
    {
      getter = getMethod(JavaVisibility.PUBLIC, ("is" + funcName), null, fieldDef.type);
    }
    
    if (getter == null)
    {
      return false;
    }
    else
    {
      JavaMethodSignature setter = getMethod(JavaVisibility.PUBLIC, ("set" + funcName), Arrays.asList(fieldDef.type), null);
      return (setter != null);
    }
  }
  
  /**
   * Retrieves the matching method for the given signature.
   * 
   * @param visiblity
   * @param name
   * @param parameters
   * @param returnType
   * @return The matching method or <code>null</code> if not found.
   */
  public JavaMethodSignature getMethod(JavaVisibility visiblity, String name, List<JavaType> parameters, JavaType returnType)
  {
    for (JavaMethodSignature method : methodSignatures)
    {
      if ((method.visibility == visiblity) 
          && (method.name.equals(name)) 
          && ((nullEmpty(method.parameterTypes)&& nullEmpty(parameters)) 
              || nullEquals(method.parameterTypes, parameters))
          && nullEquals(method.returnType, returnType))
      {
        return method;
      }
    }
    return null;
  }
 
}
